package com.leyou.search.service.impl;

import com.leyou.common.dto.PageDTO;
import com.leyou.common.exceptions.LyException;
import com.leyou.item.client.ItemClient;
import com.leyou.item.dto.SkuDTO;
import com.leyou.item.dto.SpecParamDTO;
import com.leyou.item.dto.SpuDTO;
import com.leyou.search.dto.SearchParamDTO;
import com.leyou.search.entity.Goods;
import com.leyou.search.respository.GoodsRepository;
import com.leyou.search.service.SearchService;
import com.leyou.starter.elastic.dto.PageInfo;
import com.leyou.starter.elastic.repository.Repository;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static com.leyou.search.constants.SearchConstants.*;

@Slf4j
@Service
@SuppressWarnings("ALL")
public class SearchServiceImpl implements SearchService {
    @Resource
    private GoodsRepository goodsRepository;
    @Resource
    private ItemClient itemClient;
    @Resource
    private Repository repository;


    //创建索引库并设置映射
    @Override
    public void createIndexAndMapping() {
        //1.先删除已经存在的索引库
        try {
            goodsRepository.deleteIndex();
        } catch (Exception e) {
            log.error("删除失败，可能索引库不存在！", e);
        }
        //2.创建一个新的索引库
        goodsRepository.createIndex("{\n" +
                "  \"settings\": {\n" +
                "    \"analysis\": {\n" +
                "      \"analyzer\": {\n" +
                "        \"my_pinyin\": {\n" +
                "          \"tokenizer\": \"ik_max_word\",\n" +
                "          \"filter\": [\n" +
                "            \"py\"\n" +
                "          ]\n" +
                "        }\n" +
                "      },\n" +
                "      \"filter\": {\n" +
                "        \"py\": {\n" +
                "\t\t  \"type\": \"pinyin\",\n" +
                "          \"keep_full_pinyin\": false,\n" +
                "          \"keep_joined_full_pinyin\": true,\n" +
                "          \"keep_original\": true,\n" +
                "          \"limit_first_letter_length\": 16,\n" +
                "          \"remove_duplicated_term\": true,\n" +
                "          \"none_chinese_pinyin_tokenize\": false\n" +
                "        }\n" +
                "      }\n" +
                "    }\n" +
                "  },\n" +
                "  \"mappings\": {\n" +
                "    \"properties\": {\n" +
                "      \"id\": {\n" +
                "        \"type\": \"keyword\"\n" +
                "      },\n" +
                "      \"suggestion\": {\n" +
                "        \"type\": \"completion\",\n" +
                "        \"analyzer\": \"my_pinyin\",\n" +
                "        \"search_analyzer\": \"ik_smart\"\n" +
                "      },\n" +
                "      \"title\":{\n" +
                "        \"type\": \"text\",\n" +
                "        \"analyzer\": \"my_pinyin\",\n" +
                "        \"search_analyzer\": \"ik_max_word\"\n" +
                "      },\n" +
                "      \"image\":{\n" +
                "        \"type\": \"keyword\",\n" +
                "        \"index\": false\n" +
                "      },\n" +
                "      \"updateTime\":{\n" +
                "        \"type\": \"date\"\n" +
                "      },\n" +
                "      \"specs\":{\n" +
                "        \"type\": \"nested\",\n" +
                "        \"properties\": {\n" +
                "          \"name\":{\"type\": \"keyword\" },\n" +
                "          \"value\":{\"type\": \"keyword\" }\n" +
                "        }\n" +
                "      }\n" +
                "    }\n" +
                "  }\n" +
                "}");
    }

    //加载数据到索引库
    @Override
    public void loadData() {
        //1.批量查询spu
        int page = 1;
        int rows = 100;
        while (true) {
            log.info("开始导入第{}页数据", page);
            PageDTO<SpuDTO> spuDTOPageDTO = itemClient.querySpuByPage(page, rows, true, null, null, null);
            List<SpuDTO> spuDTOList = spuDTOPageDTO.getItems();
            //2.将spu集合转换为goods对象集合
            List<Goods> goodsList = spuDTOList.stream().map(this::buildGoods).collect(Collectors.toList());
            page++;
            //3.批量写入索引库
            goodsRepository.saveAll(goodsList);
            log.info("导入第{}页数据结束。", page);
            //获取总页数,页数大于查询到的总页数则停止导入
            Long totalPage = spuDTOPageDTO.getTotalPage();
            if (page > totalPage) {
                break;
            }
        }
    }


    //查询自动补全数据
    @Override
    public Mono<List<String>> getSuggestion(String prefixKey) {
        if (StringUtils.isBlank(prefixKey)) {
            throw new LyException(400, "请求参数不能为空！");
        }
        return repository.suggestBySingleField(SUGGESTION_FIELD, prefixKey);
    }

    //分页查询商品数据
    @Override
    public Mono<PageInfo<Goods>> searchGoods(SearchParamDTO searchParamDTO) {
        //1.创建查询条件对象
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.fetchSource(DEFAULT_SOURCE_FIELD, null);//source过滤,包含，不包含
        //2.封装查询条件
        String key = searchParamDTO.getKey();
        if (StringUtils.isBlank(key)) {
            throw new LyException(400, "没有找到与“”相关的商品");
        }
        //query查询
        builder.query(QueryBuilders.boolQuery().must(QueryBuilders.matchQuery(DEFAULT_SEARCH_FIELD, key)));
        //分页条件
        builder.from(searchParamDTO.getFrom());
        builder.size(searchParamDTO.getSize());
        //排序条件
        if (StringUtils.isNotBlank(searchParamDTO.getSortBy())) {
            //排序字段存在才排序
            builder.sort(searchParamDTO.getSortBy(), searchParamDTO.getDesc() ? SortOrder.DESC : SortOrder.ASC);
        }
        //高亮条件
        builder.highlighter(new HighlightBuilder().field(DEFAULT_SEARCH_FIELD).preTags(DEFAULT_PRE_TAG).postTags(DEFAULT_POST_TAG));
        return repository.queryBySourceBuilderForPageHighlight(builder);
    }

    //新增商品到索引库
    @Override
    public void saveGoodsById(Long spuId) {
        //查询spu
        SpuDTO spuDTO = itemClient.queryGoodsById(spuId);
        //转换为goods对象
        Goods goods = buildGoods(spuDTO);
        //新增到索引库
        repository.save(goods);
    }

    //根据id删除索引库里对应商品
    @Override
    public void deleteGoodsById(Long spuId) {
        repository.deleteById(spuId);
    }

    //将查询到的Spu变为Goods对象
    private Goods buildGoods(SpuDTO spuDTO) {

        //准备Goods所需数据
        //1.自动补全的提示字段(名称，品牌，分类名称的拆分)
        Set<String> suggestion = new HashSet<>();
        suggestion.add(spuDTO.getName());
        suggestion.add(spuDTO.getBrandName());
        Collections.addAll(suggestion, spuDTO.getCategoryName().split("/"));
        //2.规格参数
        List<Map<String, Object>> specs = new ArrayList<>();
        List<SpecParamDTO> paramDTOS = itemClient.querySpecsValues(spuDTO.getId(), true);
        for (SpecParamDTO paramDTO : paramDTOS) {
            Map<String, Object> map = new HashMap<>(2);
            map.put("name", paramDTO.getName());
            map.put("value", paramDTO.getValue());
            specs.add(map);
        }
        //3.销量,同一个sku的销量总和
        //先查询sku集合
        List<SkuDTO> skuDTOList = spuDTO.getSkus();
        //判断如果没有sku,需要去查询
        if (CollectionUtils.isEmpty(skuDTOList)) {
            skuDTOList = itemClient.querySkuBySpuId(spuDTO.getId());
        }
        long soldSum = skuDTOList.stream().mapToLong(SkuDTO::getSold).sum();
        //4.sku价格合集
        Set<Long> prices = skuDTOList.stream().map(SkuDTO::getPrice).collect(Collectors.toSet());//数字可以用TreeSet
        //sku的某一个图片
//        String images = skuDTOList.get(0).getImages();
//        int i = images.indexOf(",");
//        if (i < 0) {
//            String image = images;
//        }
//        String image = images.substring(0, i);
        String image = StringUtils.substringBefore(skuDTOList.get(0).getImages(), ",");

        //创建Goods对象并设值
        Goods goods = new Goods();
        goods.setUpdateTime(new Date());
        goods.setSuggestion(suggestion);//自动补全的提示字段
        goods.setSpecs(specs);//规格参数
        goods.setSold(soldSum);//销量
        goods.setTitle(spuDTO.getTitle() + spuDTO.getCategoryName() + spuDTO.getBrandName());//标题
        goods.setPrices(prices);//sku价格合集
        goods.setImage(image);//sku的某一个图片即可
        goods.setCategoryId(spuDTO.getCid3());//分类id，只要三级分类即可
        goods.setBrandId(spuDTO.getBrandId());
        goods.setId(spuDTO.getId());
        return goods;
    }
}
